/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.itu.modernai;

import java.util.Random;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

/**
 *
 * @author Christoffer
 */
        
public class Gene implements Comparable{
    
    private float kdRate = 0;
    private float kills = 0;
    private float deaths = 0;
    private String name = "";
    
    //Constants
    public static int CHROMOSOME_SIZE = 7;   
    
    private Random rand = new Random(System.currentTimeMillis());;
    private float[] m_Chromosome = new float[CHROMOSOME_SIZE];
    
    public String getName(){
        return name;
    }
    
    public void setName(String _name){
        name = _name;
    }
    
    public Gene(){
        m_Chromosome = new float[CHROMOSOME_SIZE];
    }
    
    public Gene(Random _rand)
    {
        Initialize(_rand);
    }
    public Gene(float[] chromosome)
    {
        m_Chromosome = chromosome;
    }
    

    
    public void updateFitness(){
        kdRate = kills / deaths;
    }
    
     public void Initialize(Random _rand){
        m_Chromosome = new float[CHROMOSOME_SIZE];
        //testing health
        for(int i=0; i<CHROMOSOME_SIZE; i++){
            m_Chromosome[i] = _rand.nextFloat();
        }
        // The fourth element is now escape-while-distance
        // The last element, escape-health-threshold, should not be larger than the find-health-threshold
        m_Chromosome[4] = _rand.nextFloat() * m_Chromosome[0];
    }
    //END OF ALL "SIMPLE FUNCTIONS"
    
    
    @Override
    public String toString()
    {
        String temp = "";
        int i = 1;
        for (float f : m_Chromosome) {
            temp += f;
            if(i < m_Chromosome.length)
                temp+=",";
            i++;
        }
        
        return temp;
    }
    
    /*public void Initialize()
    {
        rand = new Random(System.currentTimeMillis());
        m_Chromosome = new float[CHROMOSOME_SIZE];
        m_fitness = 0;
        
        for (int i = 0; i < CHROMOSOME_SIZE; i++) 
        {
            m_Chromosome[i] = rand.nextFloat();
       
        }
    }*/
    
    boolean shouldFindHealth(float currentHealth){
        if(currentHealth <= m_Chromosome[0] * 100)
            return true;
        return false;
    }
    
    boolean shouldEngage(float engageDistance, float currentAmmo){
        if(engageDistance != -1 && engageDistance <= m_Chromosome[2] * 1500 - 50)
            return true;
        
        return false;
    }
    
    boolean shouldFindAmmo(float currentAmmo){
        if(currentAmmo <= m_Chromosome[1]/* * 100*/)
            return true;
        
        return false;
    }
    
    boolean shouldEscape(float currentHealth){
        return (currentHealth <= m_Chromosome[4] * 100);
    }
    //pursue!
    public STATE getPhenotype(float currentHealth, float currentAmmo, float engageDistance){
        if(shouldEscape(currentHealth)) // Now, it also has a chance to attack an enemy, depending on chromosome[6]
            return ((engageDistance != -1 && engageDistance < m_Chromosome[3] * 2000) ? rand.nextFloat() < m_Chromosome[6] ? STATE.ESCAPE : STATE.ENGAGE : STATE.HEALTH);
        if(m_Chromosome[5] > rand.nextFloat())
            return STATE.PURSUE;
        if(shouldFindHealth(currentHealth))
            return STATE.HEALTH;
        if(shouldFindAmmo(currentAmmo))
            return STATE.AMMO;
        if(shouldEngage(engageDistance, currentAmmo))
            return STATE.ENGAGE;
        
        return STATE.ROAM;
    }
    
    public void setKillsAndDeaths(float _kills, float _deaths){
        kills = _kills;
        deaths = _deaths;
    }
    
    //decode chromosome
    public float getHuntDistance()
    {
        throw new NotImplementedException();
    }
    
    public float getLookForHealthHealth()
    {
         throw  new NotImplementedException();
    }
    
    //get fitness function(s)
    public float getFitness(){ return kdRate;}
    // get value at chromosome index
    public float getChromosomeElement(int i){ return m_Chromosome[i]; }
    // set value at chromosome index
    public void setChromosomeElement(int i, float value){ m_Chromosome[i] = value; }
    
    // mutation
    public void mutate(){
        for(int i=0; i<CHROMOSOME_SIZE; i++){
            /*if(new Random().nextFloat() < GeneManager.MUTATION_RATE){
                m_Chromosome[i] = new Random().nextFloat();
            }*/
            if(new Random().nextFloat() < GeneManager.MUTATION_RATE1){
                m_Chromosome[i] = (m_Chromosome[i] - 0.1f) + (0.2f*new Random().nextFloat());
                if(m_Chromosome[i] < 0)
                    m_Chromosome[i] = 0;
                else if(m_Chromosome[i] > 1)
                    m_Chromosome[i] = 1;
            }
        }
    }
    
    // change chromosome
    public void setChromosome(float[] newChromosome){
        m_Chromosome = newChromosome;
    }
    
    public float[] getChromosome(){
        return m_Chromosome;
    }
    
    /**
     * Override method for sorting genes in the population, depending on their fitness.
     * @param otherGene gene to compare with
     * @return whether gene should be moved up or down in the hierarchy.
     */
    @Override
    public int compareTo(Object otherGene){
        //typecasting temporary Gene to compare with "this"
        Gene tempGene = (Gene)otherGene;
            
        //if 'this' fitness is worse than the other Gene's
        if(getFitness() < tempGene.getFitness()){
            //this is pushed back.
            return -1;
        }//if not:
        else if(getFitness() > tempGene.getFitness()){
            //then push to the front .
            return 1;
        }
        //if they're equal then nothing is done.
        return 0;
    }
}
